/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package GameView;

import Car.Car;
import Point.Point;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.JPanel;


/**
 *
 * @author Mirza
 */
public class RCCanvas extends JPanel{
    private Random generator = new Random(2032L);
    private final int CarWidth= 21;
    private ArrayList Data;
    private int MaxSpeed = 30;
    private int MaxLane = 10;
    private int rentang = 10;
    private int MaxCar = 12;
    private boolean end = false;
    
    /**
     * constructor
     */
    
    public RCCanvas(ArrayList _data) {
        //System.out.println("DEBUG: Size: "+_data.size());
        Data = _data;
        
        setFocusable(true);
        addKeyListener(new KeyAdapter() {
            Car mobil = (Car)Data.get(0);
            @Override
            public void keyReleased(KeyEvent e){
                int keyCode = e.getKeyCode();
                switch( keyCode ) { 
                    case KeyEvent.VK_UP    : mobil.SetVel(mobil.getVel()+1); break;
                    case KeyEvent.VK_DOWN  : if(mobil.getVel()>0) mobil.SetVel(mobil.getVel()-1);
                                             break;
                    case KeyEvent.VK_LEFT  : if(mobil.getPos().getAbsis()>0) mobil.getPos().AddAbsis(-1);
                                             break;
                    case KeyEvent.VK_RIGHT : if(mobil.getPos().getAbsis()<8) mobil.getPos().AddAbsis(1);
                                             break;
                }
            }
        });
        
        TimerTask tugas = new TimerTask(){
            int finish_line = 150;
            int tetap = 0;
            
            @Override
            public void run() {
                ++tetap;
                tetap%=100;
                repaint();
                if(Data.size() > 0){
                    //System.out.println("DEBUGUpdating..");
                    Car mobil = (Car) Data.get(0);
                    mobil.Update(rentang);
                    if (mobil.getPos().getOrdinat()>finish_line){
                        Data.remove(0);
                        end = true;
                    }
                    for (int i=1;i<Data.size();++i) {
                        mobil = (Car)Data.get(i);
                        Random randomGenerator = new Random();
                        int a = randomGenerator.nextInt(3);
                        if((a==1)&&(tetap==0)&&(mobil.getPos().getAbsis()<8)) mobil.getPos().AddAbsis(1);
                        if((a==2)&&(tetap==0)&&(mobil.getPos().getAbsis()>0)) mobil.getPos().AddAbsis(-1);
                        mobil.Update(rentang);
                        //System.out.println("DEBUGUpdated: "+x);
                        Data.set(i, mobil);
                        if (mobil.getPos().getOrdinat()>finish_line){
                            //System.out.println("DEBUGRemove OutofBounds : "+i);
                            Data.remove(i);
                        }
                    }
                int check = generator.nextInt(100);
                if (Data.size() <= MaxCar && check <= 55) {
                    AddCar();
                } 
                //Check whether there are collisions.
                CollisionChecker();
                
                //now try to ensure that in the next update
                //there wont be collisions.
                CollisionAvoiding();}
                repaint();
            }
        };
        Timer waktu= new Timer();
        waktu.schedule(tugas, 40, 60);
    }

    /**
     * set dimensi windows
     */
    @Override
    public Dimension getPreferredSize() {
        return new Dimension(215,400);
    }
    
    /**
     * paint
     */
    @Override
    public void paintComponent(Graphics g) {
        int w = 215, h = 400;
        Car x = (Car)Data.get(0);
        int base = h-250-(int)((x.getPos().getOrdinat())*CarWidth);
        g.setColor(Color.BLACK);
        g.fillRect(0, 0, w, h);
        g.setColor(Color.WHITE);
        g.drawString("ExistedCar : "+Data.size(),10,10);
        for (int i=0;i<10;++i){
            g.drawLine( 14+i*CarWidth, h-5, 14+i*CarWidth, 5);
            g.setColor(Color.BLACK);
            for(int j=1; j<h; j+=15) g.drawLine( 14+i*CarWidth, j-base%15, 14+i*CarWidth, j-5-base%15);
            g.setColor(Color.WHITE);
        }
        // g.drawString("Drawing ..", w/2, 50, Graphics.TOP | Graphics.HCENTER);
        //System.out.println("DEBUG CANVAS: Size: "+Data.size());
        for (int i=Data.size()-1;i>=0;--i) {
            x = (Car)Data.get(i);
            int xx = CarWidth+4+ (int) ((x.getPos().getAbsis())*CarWidth);
            int yy = h-(CarWidth) - (int) ((x.getPos().getOrdinat())*CarWidth);
            int[] x_point = new int[3];
            for(int j=0;j<3;++j) x_point[j] = xx+(j-1)*(CarWidth/2-2);
            int[] y_point = new int[3];
            for(int j=0;j<3;++j){
                int arah = (int) (x.getVel()/Math.abs(x.getVel()));
                if(arah==0) ++arah;
                y_point[j] = yy-arah*(j%2)*CarWidth+arah*CarWidth/2-base;
            }        
            if((i==0)&&(!end)) g.setColor(Color.RED);
            g.fillPolygon(x_point,y_point,3);
        }
        g.setColor(Color.GREEN);
        if(end) g.drawString("PERMAINAN SELESAI",45,h/2);
    }
    
    /**
     * Procedure to checked if any of the cars are colliding
     * right now.
     * Delete (destroy) them whenever necessary.
     */
    private void CollisionChecker() {   
        boolean hapus[] = new boolean[Data.size()];
        for (int i = 0;i<Data.size();++i) hapus[i] = false;

        for (int i=0;i<Data.size();++i) {
            for (int j=0;j<i;++j) {
                Point c1 = ((Car)Data.get(i)).getPos();
                Point c2 = ((Car)Data.get(j)).getPos();
                hapus[i] = hapus[i] || collide(c1,c2);
                hapus[j] = hapus[j] || collide(c1,c2);
                
                //if (collide(c1,c2)) System.out.println(c1 + " -> " + c2);
            }
        }
        
        if(hapus[0]) end=true;
        
        ArrayList<Car> survivor = new ArrayList<>();
        for (int i=0;i<Data.size();++i) {
            if (!hapus[i]) {
                survivor.add((Car)Data.get(i));
                //System.out.println("DEBUGHapus "+i);
            }
        }
        Data = survivor;
    }
    
    private boolean collide(Point a, Point b) {
        double akiri = Math.floor(a.getAbsis())-0.4;
        double abawah = Math.floor(a.getOrdinat());
        
        double bkiri = Math.floor(b.getAbsis())-0.4;
        double bbawah = Math.floor(b.getOrdinat());
        
        return (Math.max(akiri, bkiri)<=Math.min(akiri, bkiri)+0.8)&&
               (Math.max(abawah, bbawah)<=Math.min(abawah,bbawah)+1.0);
    }
    
    /**
     * procedure to avoid collision, by reducing the speed of the cars
     * whenever necessary.
     */
    private void CollisionAvoiding() {
        //boolean finish;        
        //do {
        //    finish = true;
            for (int i=0;i<Data.size();++i) {
                Car fProj = (Car)Data.get(i);
                fProj.Update(rentang);
                for (int j=0;j<Data.size();++j) {
                    if (j == i) continue;
                    Point c1 = fProj.getPos();
                    Point c2 = ((Car)Data.get(j)).getPos();
                    if ((Math.abs(c2.getAbsis()-c1.getAbsis())<1)
                            &&(c2.getOrdinat()-c1.getOrdinat()<3)
                            &&(c2.getOrdinat()-c1.getOrdinat()>0)) {
                    //if (collide(c1, c2)) {
                        //finish = false;
                        /*((Car)Data.get(j)).
                                //SetVel(Math.ceil(c2.getOrdinat())-0.1-c2.getOrdinat());
                                SetVel(0);*/
                        if(fProj.getVel()>15) fProj.SetVel(fProj.getVel()-1);
                        int belok = generator.nextInt(2);
                        if((belok==0)&&(fProj.getPos().getAbsis()==0)) belok=1;
                        if((belok==1)&&(fProj.getPos().getAbsis()==8)) belok=0;
                        if(belok==0) fProj.getPos().AddAbsis(-1); else
                        if(belok==1) fProj.getPos().AddAbsis(1);
                    }
                }
                
            }
        //} while (!finish);
    }
    
    /**
     * Procedure to add a new car to the screen.
     * Either add at the top or the bottom of the screen.
     */
    private void AddCar() {
        Data.add(new Car(new Point(generator.nextInt(MaxLane-1),-5),
                generator.nextInt(MaxSpeed-1)+1));
    }
}